package com.mmd.base.aspect;

import com.mmd.base.annotation.NoRepeatSubmit;
import com.mmd.core.enums.ResultEnum;
import com.mmd.base.exception.ApplicationException;
import com.mmd.core.utils.CommonUtils;
import com.mmd.base.utils.IPUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class NoRepeatSubmitAOP {
    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.mmd.base.annotation.NoRepeatSubmit)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(attributes,"请求异常,请联系管理员!");
        HttpServletRequest request = attributes.getRequest();
        Assert.notNull(request, "获取请求失败,请联系管理员!");
        // 此处可以用token
        String ip = IPUtils.getIp(request);
        String authentication = CommonUtils.isEmptyDefault(request.getHeader("Authentication"),"");
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder stringBuilder = new StringBuilder();
        parameterMap.forEach((k,v)->{
                    stringBuilder.append(k).append(Arrays.toString(v));
                }
        );
        String key = ip + authentication + "-" + request.getServletPath()+"-"+stringBuilder;
        NoRepeatSubmit annotation = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(NoRepeatSubmit.class);
        long expire = annotation.value();
        //加锁 超时时间：10秒，最好设为常量
        RLock lock = redissonClient.getLock(key);
        if (lock.tryLock(0,expire, TimeUnit.MILLISECONDS)) {
            // 这里不进行解锁 设置多少秒就限制多少秒
            return pjp.proceed();
        } else {
            throw new ApplicationException(ResultEnum.FAIL_REQUEST_REPETITION);
        }
    }
}

